<template>
  <div class="captcha-container">
    <canvas 
      ref="captchaCanvas" 
      :width="width" 
      :height="height" 
      @click="generateCaptcha"
      class="captcha-canvas"
      title="点击刷新验证码"
    ></canvas>
    <el-button 
      type="text" 
      @click="generateCaptcha" 
      class="refresh-btn"
      title="刷新验证码"
    >
      <el-icon><Refresh /></el-icon>
    </el-button>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, nextTick } from 'vue'
import { Refresh } from '@element-plus/icons-vue'

interface Props {
  width?: number
  height?: number
  length?: number
}

const props = withDefaults(defineProps<Props>(), {
  width: 120,
  height: 40,
  length: 4
})

const emit = defineEmits<{
  change: [code: string]
}>()

const captchaCanvas = ref<HTMLCanvasElement>()
const captchaCode = ref('')

// 生成随机字符
const generateRandomChar = () => {
  const chars = 'ABCDEFGHJKMNPQRSTUVWXYZabcdefhijkmnpqrstuvwxyz23456789'
  return chars.charAt(Math.floor(Math.random() * chars.length))
}

// 生成随机颜色
const getRandomColor = () => {
  const r = Math.floor(Math.random() * 256)
  const g = Math.floor(Math.random() * 256)
  const b = Math.floor(Math.random() * 256)
  return `rgb(${r}, ${g}, ${b})`
}

// 生成验证码
const generateCaptcha = () => {
  const canvas = captchaCanvas.value
  if (!canvas) return

  const ctx = canvas.getContext('2d')
  if (!ctx) return

  // 清空画布
  ctx.clearRect(0, 0, props.width, props.height)

  // 设置背景
  ctx.fillStyle = '#f8f9fa'
  ctx.fillRect(0, 0, props.width, props.height)

  // 生成验证码字符串
  let code = ''
  for (let i = 0; i < props.length; i++) {
    code += generateRandomChar()
  }
  captchaCode.value = code

  // 绘制字符
  const fontSize = props.height * 0.6
  ctx.font = `${fontSize}px Arial`
  ctx.textBaseline = 'middle'

  for (let i = 0; i < code.length; i++) {
    const char = code[i]
    const x = (props.width / props.length) * i + (props.width / props.length) * 0.2
    const y = props.height / 2

    // 随机颜色
    ctx.fillStyle = getRandomColor()
    
    // 随机旋转
    ctx.save()
    ctx.translate(x + fontSize / 2, y)
    ctx.rotate((Math.random() - 0.5) * 0.4)
    ctx.fillText(char, 0, 0)
    ctx.restore()
  }

  // 添加干扰线
  for (let i = 0; i < 3; i++) {
    ctx.strokeStyle = getRandomColor()
    ctx.lineWidth = 1
    ctx.beginPath()
    ctx.moveTo(Math.random() * props.width, Math.random() * props.height)
    ctx.lineTo(Math.random() * props.width, Math.random() * props.height)
    ctx.stroke()
  }

  // 添加干扰点
  for (let i = 0; i < 20; i++) {
    ctx.fillStyle = getRandomColor()
    ctx.beginPath()
    ctx.arc(
      Math.random() * props.width,
      Math.random() * props.height,
      1,
      0,
      2 * Math.PI
    )
    ctx.fill()
  }

  // 通知父组件验证码已更新
  emit('change', code.toLowerCase())
}

// 验证输入的验证码
const validate = (inputCode: string) => {
  return inputCode.toLowerCase() === captchaCode.value.toLowerCase()
}

// 暴露验证方法给父组件
defineExpose({
  validate,
  refresh: generateCaptcha
})

onMounted(() => {
  nextTick(() => {
    generateCaptcha()
  })
})
</script>

<style scoped>
.captcha-container {
  display: flex;
  align-items: center;
  gap: 8px;
}

.captcha-canvas {
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  cursor: pointer;
  transition: border-color 0.3s;
}

.captcha-canvas:hover {
  border-color: #409eff;
}

.refresh-btn {
  padding: 0;
  font-size: 16px;
  color: #606266;
}

.refresh-btn:hover {
  color: #409eff;
}
</style> 